/*************************************************************************
** Copyright (C) 2014  Mario Marquez <maqzma@gmail.com>.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*************************************************************************/

#ifndef TIMER_H
#define TIMER_H

#include <thread>
#include <chrono>
#include <atomic>

/**
 * Temporizador.
 *
 * Ejecuta la funcion timeout cada vez
 * que un ciclo termina.
 *
 * Se le llama singleShot al temporizador
 * que solo cuenta con un solo ciclo.
 *
 * Detener el temporizador a medio ciclo
 * dentendra la ultima ejecucion del timeout.
 *
 * Iniciar un temporizador ya iniciado
 * resulta en una operacion nula, no hace
 * nada. Lo mismo al detener un temporizador.
 *
 * Por motivos de seguridad es imposible
 * modificar las propiedades del objeto
 * mientras el temporizador esta corriendo.
 */
class Timer
{
public:
    typedef std::chrono::milliseconds Interval;
    typedef std::function<void(void)> Timeout;

    Timer();
    Timer(const Timeout &timeout);
    Timer(const Timeout &timeout,
          const Interval &interval,
          bool singleShot = true);

    // Aseguramos la correcta finalizacion del hilo.
    ~Timer();

    void start();
    void stop();

    bool running() const;

    void setSingleShot(bool singleShot);
    bool isSingleShot() const;

    void setInterval(const Interval &interval);
    const Interval &interval() const;

    void setTimeout(const Timeout &timeout);
    const Timeout &timeout() const;

    Timer(const Timer &) = delete;
    Timer &operator = (const Timer &) = delete;

private:
    std::thread _thread;

    std::atomic<bool> _running;
    bool _isSingleShot = true;

    Interval _interval = Interval(0);
    Timeout _timeout = nullptr;

    void _temporize();
    void _sleepThenTimeout();
};

#endif // TIMER_H
